#include "LMWorkProxy.h"
#include "../proto/workitem.pb.h"
#include "../master/LMMaster.h"

LMWorkerProxy::LMWorkerProxy(boost::shared_ptr<boost::asio::ip::tcp::socket> socket, LMMaster* master)
	: _socket(socket)
	, _master(master)
{

}

LMWorkerProxy::~LMWorkerProxy()
{

}

bool LMWorkerProxy::isOnline()
{
	return true;
}

void LMWorkerProxy::start()
{
	_workThr.reset(new boost::thread(boost::bind(&LMWorkerProxy::workThread, this)));
}

void LMWorkerProxy::workThread()
{
	std::cout << "Remote worker: " << _socket->remote_endpoint().address() << " starting..." << std::endl;

	for(;;)
	{
		boost::system::error_code ec;

		// read size
		int size_buf;
		int recvd = _socket->read_some(boost::asio::buffer((char *)(&size_buf), 4), ec);
		if(ec == boost::asio::error::would_block)
		{
			Sleep(10);
			continue;
		}
		std::cout << "Get from worker, size: " << recvd << std::endl;
		
		boost::scoped_array<char> body_buf(new char[size_buf]);
		recvd = 0;
		while(recvd < size_buf)
		{
			recvd += _socket->read_some(boost::asio::buffer(body_buf.get(), size_buf));
		}

		protoXptShareToSubmit proto_sts;
		proto_sts.ParseFromArray(body_buf.get(), size_buf);
		std::cout << "Get protoXptShareToSubmit:" << proto_sts.ShortDebugString() << std::endl;

		LMMaster::xptShareToSubmit_t* spt_sts = new LMMaster::xptShareToSubmit_t;
		spt_sts->algorithm = proto_sts.algorithm();
		for(int i = 0; i < 32; ++i)
			spt_sts->merkleRoot[i] = proto_sts.merkleroot(i);

		for(int i = 0; i < 32; ++i)
			spt_sts->prevBlockHash[i] = proto_sts.prevblockhash(i);

		spt_sts->version = proto_sts.version();

		spt_sts->nonce = proto_sts.nonce();

		spt_sts->nTime = proto_sts.ntime();

		spt_sts->nBits = proto_sts.nbits();

		spt_sts->sieveSize = proto_sts.sievesize();

		spt_sts->sieveCandidate = proto_sts.sievecandidate();

		spt_sts->fixedMultiplierSize = proto_sts.fixedmultipliersize();

		for(int i = 0; i < 201; ++i)
			spt_sts->fixedMultiplier[i] = proto_sts.fixedmultiplier(i);

		spt_sts->chainMultiplierSize = proto_sts.chainmultipliersize();
		
		for(int i = 0; i < 201; ++i)
			spt_sts->chainMultiplier[i] = proto_sts.chainmultiplier(i);

		spt_sts->nBirthdayA = proto_sts.nbirthdaya();
		
		spt_sts->nBirthdayB = proto_sts.nbirthdayb();
		
		for(int i = 0; i < 32; ++i)
			spt_sts->riecoin_nOffset[i] = proto_sts.riecoin_noffset(i);

		for(int i = 0; i < 32; ++i)
			spt_sts->merkleRootOriginal[i] = proto_sts.merklerootoriginal(i);

		spt_sts->userExtraNonceLength = proto_sts.userextranoncelength();
		
		for(int i = 0; i < 16; ++i)
			spt_sts->userExtraNonceData[i] = proto_sts.userextranoncedata(i);

		_master->foundShare(spt_sts);
	}
	

}

void LMWorkerProxy::updateWork(ProtoXptBlockWorkInfo *work)
{
	boost::lock_guard<boost::mutex> locker(_socketMutex);

	std::string outstr;
	work->SerializeToString(&outstr);

	char sizebuf[4];
	*((int *)(sizebuf)) = outstr.size();
	int writed = 0;
	while(writed < 4)
		_socket->write_some(boost::asio::buffer(sizebuf + writed, 4 - writed));

	writed = 0;
	while(writed < outstr.size())
		_socket->write_some(boost::asio::buffer(outstr.c_str() + writed, outstr.size() - writed));
}
